package net.kazed.nextaction.task;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.kazed.android.inject.ApplicationContext;
import net.kazed.nextaction.ApplicationResource;
import net.kazed.nextaction.NextActionApplication;
import net.kazed.nextaction.R;
import net.kazed.nextaction.context.activity.ContextView2Activity;
import net.kazed.nextaction.context.activity.ContextsActivity;
import net.kazed.nextaction.database.ContextCache;
import net.kazed.nextaction.database.GtdContext;
import net.kazed.nextaction.database.Task;
import net.kazed.nextaction.database.TaskStatus;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * Activity to edit a Task.
 * @author Koert Zeilstra
 */
public class TaskEditorActivity extends Activity {

    private static final String TAG = "TaskEditorActivity";
    
    private static final int MENU_REVERT = Menu.FIRST;
    private static final int MENU_DELETE = Menu.FIRST + 1;
    private static final int MENU_INSERT_ATTACHMENT = MENU_DELETE + 1;
    private static final int START_DATE_DIALOG = 0;
    private static final int DUE_DATE_DIALOG = 1;
    private static final int ADD_ATTACHMENT_DIALOG = 2;
    private static final int ADD_ATTACHMENT_DIALOG2 = 3;
    
    private static final int PICK_PARENT = 1;

    private String action;
    private Cursor cursor;
    private boolean isNew;
    private Uri itemUri;
    private long selectedContextId;
    private Task originalTask;
    private Task parentTask;
    private List<GtdContext> contextList;
    private ApplicationResource applicationResource;
    private Map<Integer, TaskStatus> positionToTypeMap;
    private Map<TaskStatus, Integer> typeToPositionMap;
    private TaskAttachmentManager taskAttachmentManager;
    private ListAdapter listAdapter;
    private AlertDialog alertDialog;
    private int selectedAttachmentTypeIndex;

    private RelativeLayout parentGroup;
    private TextView parentDescription;
    private Button parentChoose;
    private EditText nameWidget;
    private Spinner typeSpinner;
    private CheckBox completedWidget;
    private Spinner contextSpinner;
    private DateInput startDateInput;
    private DateInput dueDateInput;
    private EditText noteWidget;
    private Button saveButton;
    private Button cancelButton;
    private SpecialAction onResumeAction;

        
    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        
        Resources resources = getResources();
        
        final Intent intent = getIntent();
        action = intent.getAction();
        selectedContextId = intent.getLongExtra(GtdContext.SELECTED_CONTEXT_ID, 0);
        if (action.equals(Intent.ACTION_EDIT)) {
            isNew = false;
            itemUri = intent.getData();
            setResult(RESULT_OK, intent);
        } else if (action.equals(Intent.ACTION_INSERT)) {
           isNew = true;
           itemUri = intent.getData();

           if (itemUri == null) {
              Log.e(TAG, "Failed to insert new item into "
                    + getIntent().getData());
              finish();
              return;
           }
           // KZ - put this in onSaveInstanceState or onPause ?
          Bundle bundle = new Bundle();
          bundle.putString(ContextsActivity.SELECTED_ITEM, itemUri.toString());
          Intent mIntent = new Intent(Intent.ACTION_EDIT, itemUri);
          mIntent.putExtras(bundle);
          setResult(RESULT_OK, mIntent);
        } else {
            finish();
            return;
        }

        cursor = managedQuery(itemUri, Task.FULL_PROJECTION.getFieldNames(), null, null, null);
        
        setContentView(R.layout.task_editor);
        parentGroup = (RelativeLayout) findViewById(R.id.parent_group);
        parentDescription = (TextView) findViewById(R.id.parent_description);
        parentChoose = (Button) findViewById(R.id.task_parent_choose_button);
        
        nameWidget = (EditText) findViewById(R.id.description);
        typeSpinner = (Spinner) findViewById(R.id.task_type_spinner);
        completedWidget = (CheckBox) findViewById(R.id.completed_checkbox);
        contextSpinner = (Spinner) findViewById(R.id.context_spinner);
        
        startDateInput = new DateInput(this, R.id.start_date_display, R.id.start_date_set_button, R.id.start_date_clear_button,
                        START_DATE_DIALOG);
        dueDateInput = new DateInput(this, R.id.due_date_display, R.id.due_date_set_button, R.id.due_date_clear_button,
                        DUE_DATE_DIALOG);
        noteWidget = (EditText) findViewById(R.id.notes);
        
        parentChoose.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (parentTask == null) {
                    Intent intent = new Intent(ContextView2Activity.PICK_TASK, GtdContext.CONTENT_URI);
                    startActivityForResult(intent, PICK_PARENT);
                } else {
                    parentTask = null;
                    originalTask.setParentTaskId(null);
                    updateTask(originalTask);
                    populateFields(originalTask);
                }
            }
         });
        
        saveButton = (Button) findViewById(R.id.save_button);
        saveButton.setOnClickListener(new View.OnClickListener() {
           public void onClick(View v) {
              saveTask();
              finish();
           }
        });
        
        cancelButton = (Button) findViewById(R.id.cancel_button);
        cancelButton.setOnClickListener(new View.OnClickListener() {
           public void onClick(View v) {
              if (isNew) {
                 getContentResolver().delete(itemUri, null, null);
              }
              finish();
           }
        });
        
        if (action.equals(Intent.ACTION_EDIT)) {
            parentGroup.setVisibility(View.VISIBLE);
        } else {
            parentGroup.setVisibility(View.GONE);
        }

        NextActionApplication application = (NextActionApplication) getApplication();
        applicationResource = application.getApplicationResource();
        
        positionToTypeMap = new HashMap<Integer, TaskStatus>();
        typeToPositionMap = new HashMap<TaskStatus, Integer>();
        List<TaskStatus> actionTypes = applicationResource.getActionTypes();
        String[] taskTypes = new String[actionTypes.size()];
        int taskIndex = 0;
        for (TaskStatus type : actionTypes) {
            taskTypes[taskIndex] = resources.getString(applicationResource.getTaskTypeName(type));
            positionToTypeMap.put(taskIndex, type);
            typeToPositionMap.put(type, taskIndex);
            taskIndex++;
        }
        ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                        android.R.id.text1, taskTypes);
        typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        typeSpinner.setAdapter(typeAdapter);
                  
        ContextCache contextCache = application.getContextCache(); //new ContextCache(getContentResolver());

        List<GtdContext> contextsFromTree = contextCache.getFlattenedContextTree();
        contextList = new ArrayList<GtdContext>(contextsFromTree.size() + 1);
        String inboxTitle = getResources().getString(R.string.inbox_title);
        GtdContext inboxContext = new GtdContext(inboxTitle);
        contextList.add(inboxContext);
        contextList.addAll(contextCache.getFlattenedContextTree());

        ContentResolver resolver = getContentResolver();
        List<String> contextNameList = new ArrayList<String>(contextList.size());
        int i = 0;
        int selectedContextPosition = 0;
        for (Iterator<GtdContext> contextIterator = contextList.iterator(); contextIterator.hasNext();) {
           GtdContext context = (GtdContext) contextIterator.next();
           contextNameList.add(context.getAbsoluteContextPath(resolver, "/"));
           if (context.getId() != null && selectedContextId == context.getId()) {
              selectedContextPosition = i;
           }
           i++;
        }
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,
                        android.R.id.text1, contextNameList);
        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        contextSpinner.setAdapter(arrayAdapter);
        contextSpinner.setSelection(selectedContextPosition, true);

        ApplicationContext appContext = application.getAppContext();
//        long start = System.currentTimeMillis();
        taskAttachmentManager = appContext.getBean(TaskAttachmentManager.class);
//        long duration = System.currentTimeMillis() - start;
//        Toast.makeText(getApplicationContext(), "duration: " + duration, Toast.LENGTH_SHORT).show();
    }
    
    @Override
    protected void onResume() {
        Log.d(TAG, "onResume+");
        super.onResume();

        if (cursor != null) {
            cursor.moveToFirst();
            if (isNew) {
               setTitle(R.string.title_new_task);
            } else {
               setTitle(R.string.title_edit_task);
            }

            originalTask = new Task(cursor);
            if (originalTask.getParentTaskId() != null) {
                Uri parentItem = ContentUris.withAppendedId(Task.CONTENT_URI, originalTask.getParentTaskId());
                Cursor parentCursor = managedQuery(parentItem, Task.FULL_PROJECTION.getFieldNames(), null, null, null);
                if (parentCursor.moveToFirst()) {
                    parentTask = new Task(parentCursor);
                }
                parentCursor.close();
            }
            
            populateFields(originalTask);
        } else {
            setTitle(getText(R.string.error_title));
            nameWidget.setText(getText(R.string.error_message));
        }
        
        if (onResumeAction != null) {
            onResumeAction.execute();
        }
        nameWidget.selectAll();
    }

   private void populateFields(Task task) {
       if (parentTask == null) {
           parentChoose.setText(R.string.task_parent_choose_button_title);
           parentDescription.setText(R.string.project_none);
       } else {
           parentChoose.setText(R.string.task_parent_detach_button_title);
           parentDescription.setText(parentTask.getDescription());
       }

      nameWidget.setTextKeepState(task.getDescription() == null ? "" : task.getDescription());
      completedWidget.setChecked(task.getComplete());
      startDateInput.setDate(task.getStartDate());
      dueDateInput.setDate(task.getDueDate());
      noteWidget.setTextKeepState(task.getDetails());
      
      Integer contextId = task.getContextId();
      if (contextId != null) {
         int i = 0;
         for (Iterator<GtdContext> contextIterator = contextList.iterator(); contextIterator.hasNext();) {
            GtdContext context = contextIterator.next();
            if (contextId.equals(context.getId())) {
               contextSpinner.setSelection(i);
               break;
            }
            i++;
         }
      }
      TaskStatus type = task.getStatus(TaskStatus.UNPROCESSED);
      typeSpinner.setSelection(typeToPositionMap.get(type));
   }
    
   @Override
   protected Dialog onCreateDialog(int id) {
       Dialog dialog = null;
       switch (id) {
       case START_DATE_DIALOG:
           dialog = startDateInput.createDialog();
           break;
       case DUE_DATE_DIALOG:
           dialog = dueDateInput.createDialog();
           break;
       case ADD_ATTACHMENT_DIALOG:
           listAdapter = taskAttachmentManager.getAttachmentTypeListAdapter(getApplicationContext(),
                           android.R.layout.select_dialog_singlechoice);
           alertDialog = new AlertDialog.Builder(this)
//               .setIcon(android.R.drawable.alert_dialog_icon)
               .setTitle(R.string.add_attachment_dialog_title)
               .setSingleChoiceItems(listAdapter, selectedAttachmentTypeIndex, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       selectedAttachmentTypeIndex = whichItem;
                   }
               })
               .setPositiveButton(R.string.ok_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       AttachmentType attachmentType = taskAttachmentManager.getActiveAttachmentType(selectedAttachmentTypeIndex);
                       Intent intent = attachmentType.getIntent();
                       startActivityForResult(intent, attachmentType.getRequestCode());
                   }
               })
               .setNegativeButton(R.string.cancel_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       /* User clicked No so do some stuff */
                   }
               })
              .create();
               dialog = alertDialog;
               break;
       case ADD_ATTACHMENT_DIALOG2:
           listAdapter = taskAttachmentManager.getAttachmentTypeListAdapter(getApplicationContext(),
                           android.R.layout.select_dialog_singlechoice);
           alertDialog = new AlertDialog.Builder(this)
               .setTitle(R.string.add_attachment_dialog_title)
               .setSingleChoiceItems(listAdapter, selectedAttachmentTypeIndex, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       selectedAttachmentTypeIndex = whichItem;
                   }
               })
               .setPositiveButton(R.string.ok_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       AttachmentType attachmentType = taskAttachmentManager.getActiveAttachmentType(selectedAttachmentTypeIndex);
                       Intent intent = attachmentType.getIntent();
                       startActivityForResult(intent, attachmentType.getRequestCode());
                   }
               })
               .setNegativeButton(R.string.cancel_button_title, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int whichItem) {
                       /* User clicked No so do some stuff */
                   }
               })
              .create();
               dialog = alertDialog;
               break;

       }
       
       return dialog;
   }

   @Override
   protected void onPrepareDialog(int id, Dialog dialog) {
       switch (id) {
       case START_DATE_DIALOG:
           startDateInput.updateDialog(dialog);
           break;
       case DUE_DATE_DIALOG:
           dueDateInput.updateDialog(dialog);
           break;
       }
   }

    @Override
	protected void onActivityResult(int requestCode, int resultCode,
			Intent data) {

        if (resultCode == RESULT_OK) {
            switch (requestCode) {
            case PICK_PARENT:
                Uri uri = data.getData();
                int parentTaskId = (int) ContentUris.parseId(uri);
                originalTask.setParentTaskId(parentTaskId);
                updateTask(originalTask);
                break;
            default:
                AttachmentType type = taskAttachmentManager.getAttachmentTypeByRequestCode(requestCode);
                if (type != null) {
                    String link = type.getAttachmentLink(this, data);
                    String noteText = noteWidget.getText().toString();
                    int start = noteWidget.getSelectionStart();
                    if (start < 0) {
                        noteText = noteText + link;
                    } else {
                        noteText = noteText.substring(0, start) + link + noteText.substring(start);
                    }
                    final String t = noteText;
                    onResumeAction = new SpecialAction() {
                        public void execute() {
                            noteWidget.setTextKeepState(t);
                            onResumeAction = null;
                        }
                    };
                }
            }
        }
	}

    /**
     * Update task in database.
     * @param task Task.
     */
    private void updateTask(Task task) {
        ContentValues values = new ContentValues();
        task.toValues(values);
        getContentResolver().update(itemUri, values, null, null);
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        saveTask();
    }

    /**
     * Save current task.
     */
   private void saveTask() {
//      if (cursor != null) {
//            Task task = new Task(cursor);
            Task task = originalTask;
            if (isNew) {
               task.setContextId((int) selectedContextId);
            }
            task.setDescription(nameWidget.getText().toString());
            TaskStatus type = positionToTypeMap.get(typeSpinner.getSelectedItemPosition());
            if (type == null) {
                type = TaskStatus.UNPROCESSED;
            }
            task.setStatus(type);
            task.setComplete(completedWidget.isChecked());
            task.setDetails(noteWidget.getText().toString());
            int contextPosition = contextSpinner.getSelectedItemPosition();
            if (contextPosition < contextList.size()) {
               GtdContext context = contextList.get(contextPosition);
               task.setContextId(context.getId());
            }
            task.setStartDate(startDateInput.getDate());
            task.setDueDate(dueDateInput.getDate());
            ContentValues values = new ContentValues();
            task.toValues(values);
            getContentResolver().update(itemUri, values, null, null);
//        }
   }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       Resources resources = getResources();
       int order = 0;
       if (noteWidget.isFocused()) {
           menu.add(0, MENU_INSERT_ATTACHMENT, order++, resources.getString(R.string.menu_add_attachment))
           .setIcon(android.R.drawable.ic_menu_add).setAlphabeticShortcut('i');
       }
       menu.add(0, MENU_REVERT, order++, resources.getString(R.string.menu_revert))
          .setIcon(android.R.drawable.ic_menu_revert).setAlphabeticShortcut('r');
       menu.add(0, MENU_DELETE, order++, resources.getString(R.string.menu_delete))
          .setIcon(android.R.drawable.ic_menu_delete).setAlphabeticShortcut('d');
       return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       switch (item.getItemId()) {
       case MENU_INSERT_ATTACHMENT:
           showDialog(ADD_ATTACHMENT_DIALOG);
           break;
       case MENU_REVERT:
           populateFields(originalTask);
           break;
       case MENU_DELETE:
           AlertDialog.Builder builder = new AlertDialog.Builder(TaskEditorActivity.this);
           builder.setTitle(R.string.task_delete_alert_title).setMessage(R.string.task_delete_alert_message)
               .setIcon(android.R.drawable.ic_dialog_alert);
           builder.setPositiveButton(R.string.alert_yes, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int whichButton) {
                   getContentResolver().delete(itemUri, null, null);
                   finish();
               }
           });
           builder.setNegativeButton(R.string.alert_no, null);
           builder.show();
           break;
       }
       return super.onOptionsItemSelected(item);
    }
    
    /**
     * Take care of deleting a context.  Simply deletes the entry.
     */
    protected void deleteItem() {
       nameWidget.setText("");
    }
    
    private interface SpecialAction {
        void execute();
    }
}
